﻿#include "byteutil.h"

ByteUtil::ByteUtil()
{
}


unsigned char ByteUtil::getBits(unsigned char data, int low, int high)
{
    // 获取字节的指定位的值，算法的思想是:先对这个字节从high位至第7位处理为0,然后对这个处理后的字节逻辑右移low位.
    unsigned char bits = data;  //初始化为整个字节
    if (low < 0 || high > 7 || low > high)
        return 0;

    for (int i = high + 1; i < 8; i++) {
        switch (i) {
        case 0:  //将字节的第0位置0
            bits &= 0xFE;
            break;
        case 1:  //将字节的第1位置0
            bits &= 0xFD;
            break;
        case 2:  //将字节的第2位置0
            bits &= 0xFB;
            break;
        case 3:  //将字节的第3位置0
            bits &= 0xF7;
            break;
        case 4:  //将字节的第4位置0
            bits &= 0xEF;
            break;
        case 5:  //将字节的第5位置0
            bits &= 0xDF;
            break;
        case 6:  //将字节的第6位置0
            bits &= 0xBF;
            break;
        case 7:  //将字节的第7位置0
            bits &= 0x7F;
            break;
        default:
            break;
        }
    }

    bits >>= low;  //将字节右移low位
    return bits;
}

unsigned short ByteUtil::toUInt16(QByteArray& data, int offset, Endian endian)
{
    if (data.size() < 2 || data.size() < offset + 2)
        return 0;

    unsigned short value = 0;
    if (endian == LittileEndian) {  //小端
         value = data.at(offset) & 0xFF;
         value |= (data.at(offset + 1) << 8) & 0xFF00;
    } else {  //大端
        value = (data.at(offset) << 8) & 0xFF00;
        value |= data.at(offset + 1) & 0xFF;
    }

    return value;
}

short ByteUtil::toInt16(QByteArray& data, int offset, Endian endian)
{
    if (data.size() < 2 || data.size() < offset + 2)
        return 0;

    unsigned short value = 0;
    if (endian == LittileEndian) {  //小端
         value = data.at(offset) & 0xFF;
         value |= (data.at(offset + 1) << 8) & 0x7F00;

         return getBits(data.at(offset + 1), 7, 7) == 0 ? value : -value;
    } else {  //大端
        value = (data.at(offset) << 8) & 0x7F00;
        value |= data.at(offset + 1) & 0xFF;

        return getBits(data.at(offset), 7, 7) == 0 ? value : -value;
    }
}

unsigned int ByteUtil::toUInt32(QByteArray& data, int offset, Endian endian)
{
    if (data.size() < 4 || data.size() < offset + 4)
        return 0;

    unsigned int value = 0;
    if (endian == LittileEndian) {  //小端
        value = data.at(offset) & 0xFF;
        value |= (data.at(offset + 1) << 8) & 0xFF00;
        value |= (data.at(offset + 2) << 16) & 0xFF0000;
        value |= (data.at(offset + 3) << 24) & 0xFF000000;
    } else {  //大端
        value = (data.at(offset) << 24) & 0xFF000000;
        value |= (data.at(offset + 1) << 16) & 0xFF0000;
        value |= (data.at(offset + 2) << 8) & 0xFF00;
        value |= data.at(offset + 3) & 0xFF;
    }

    return value;
}

int ByteUtil::toInt32(QByteArray& data, int offset, Endian endian)
{
    if (data.size() < 4 || data.size() < offset + 4)
        return 0;

    int value = 0;
    if (endian == LittileEndian) {  //小端
        value = data.at(offset) & 0xFF;
        value |= (data.at(offset + 1) << 8) & 0xFF00;
        value |= (data.at(offset + 2) << 16) & 0xFF0000;
        value |= (data.at(offset + 3) << 24) & 0x7F000000;

        return getBits(data.at(offset + 3), 7, 7) == 0 ? value : -value;
    } else {  //大端
        value = (data.at(offset) << 24) & 0x7F000000;
        value |= (data.at(offset + 1) << 16) & 0xFF0000;
        value |= (data.at(offset + 2) << 8) & 0xFF00;
        value |= data.at(offset + 3) & 0xFF;

        return getBits(data.at(offset), 7, 7) == 0 ? value : -value;
    }

    return value;
}

unsigned long ByteUtil::toUInt64(QByteArray& data, int offset, Endian endian)
{
    if (data.size() < 8 || data.size() < offset + 8)
        return 0;

    unsigned int low = 0;  //低4字节
    unsigned int high = 0;  //高4字节
    unsigned long long value = 0;
    if (endian == LittileEndian) {  //小端
        low = data.at(offset) & 0xFF;
        low |= (data.at(offset + 1) << 8) & 0xFF00;
        low |= (data.at(offset + 2) << 16) & 0xFF0000;
        low |= (data.at(offset + 3) << 24) & 0xFF000000;

        high |= data.at(offset + 4) & 0xFF;
        high |= (data.at(offset + 5) << 8) & 0xFF00;
        high |= (data.at(offset + 6) << 16) & 0xFF0000;
        high |= ((data.at(offset + 7) << 24)) & 0xFF000000;

        value = 2 * ((high << 31) & 0x7FFFFFFF00000000) + low;
    } else {  //大端
         high = (data.at(offset) << 24) & 0xFF000000;
         high |= (data.at(offset + 1) << 16) & 0xFF0000;
         high |= (data.at(offset + 2) << 8) & 0xFF00;
         high |= data.at(offset + 3) & 0xFF;

         low |= (data.at(offset + 4) << 24) & 0xFF000000;
         low |= (data.at(offset + 5) << 16) & 0xFF0000;
         low |= (data.at(offset + 6) << 8) & 0xFF00;
         low |= data.at(offset + 7) & 0xFF;

         value = 2 * ((high << 31) & 0x7FFFFFFF00000000) + low;
    }

    return value;
}

long ByteUtil::toInt64(QByteArray& data, int offset, Endian endian)
{
    if (data.size() < 8 || data.size() < offset + 8)
        return 0;

    unsigned int low = 0;  //低4字节
    unsigned int high = 0;  //高4字节
    long long value = 0;
    if (endian == LittileEndian) {  //小端
        low = data.at(offset) & 0xFF;
        low |= (data.at(offset + 1) << 8) & 0xFF00;
        low |= (data.at(offset + 2) << 16) & 0xFF0000;
        low |= (data.at(offset + 3) << 24) & 0xFF000000;

        high |= data.at(offset + 4) & 0xFF;
        high |= (data.at(offset + 5) << 8) & 0xFF00;
        high |= (data.at(offset + 6) << 16) & 0xFF0000;
        high |= ((data.at(offset + 7) << 24)) & 0xFF000000;

        value = ((high << 31) & 0x7FFFFFFF00000000) + low;

        return getBits(data.at(offset + 7), 7, 7) == 0 ? value : -value;
    } else {  //大端
         high = (data.at(offset) << 24) & 0xFF000000;
         high |= (data.at(offset + 1) << 16) & 0xFF0000;
         high |= (data.at(offset + 2) << 8) & 0xFF00;
         high |= data.at(offset + 3) & 0xFF;

         low |= (data.at(offset + 4) << 24) & 0xFF000000;
         low |= (data.at(offset + 5) << 16) & 0xFF0000;
         low |= (data.at(offset + 6) << 8) & 0xFF00;
         low |= data.at(offset + 7) & 0xFF;

         value = ((high << 31) & 0x7FFFFFFF00000000) + low;

         return getBits(data.at(offset), 7, 7) == 0 ? value : -value;
    }
}

float ByteUtil::toFloat(QByteArray& data, int offset, Endian endian)
{
    if (data.size() < 4 || data.size() < offset + 4)
        return 0;

    typedef struct tagSFloat {
        unsigned char low;
        unsigned char midlow;
        unsigned char midhigh;
        unsigned char high;
    } SFloat;

    typedef union tagUFloat {
        SFloat s;
        float f;
    } UFloat;

    UFloat uf;
    if (endian == LittileEndian) {  //小端
        //memcpy(&value, data.data() + offset, sizeof(float));
        uf.s.low = data.at(offset);
        uf.s.midlow = data.at(offset + 1);
        uf.s.midhigh = data.at(offset + 2);
        uf.s.high = data.at(offset + 3);
    } else {  //大端
        //memcpy(&value, data.data() + offset, sizeof(float));
        uf.s.low = data.at(offset + 3);
        uf.s.midlow = data.at(offset + 2);
        uf.s.midhigh = data.at(offset + 1);
        uf.s.high = data.at(offset);
    }

    return uf.f;
}

double ByteUtil::toDouble(QByteArray& data, int offset, Endian endian)
{
    if (data.size() < 8 || data.size() < offset + 8)
        return 0;

    typedef struct tagSDouble {
        unsigned char byte0;
        unsigned char byte1;
        unsigned char byte2;
        unsigned char byte3;
        unsigned char byte4;
        unsigned char byte5;
        unsigned char byte6;
        unsigned char byte7;
    } SDouble;

    typedef union tagUDouble {
        SDouble s;
        double dbl;
    } UDouble;

    UDouble udbl;
    if (endian == LittileEndian) {  //小端
        //memcpy(&value, data.data() + offset, sizeof(double));
        udbl.s.byte0 = data.at(offset);
        udbl.s.byte1 = data.at(offset + 1);
        udbl.s.byte2 = data.at(offset + 2);
        udbl.s.byte3 = data.at(offset + 3);
        udbl.s.byte4 = data.at(offset + 4);
        udbl.s.byte5 = data.at(offset + 5);
        udbl.s.byte6 = data.at(offset + 6);
        udbl.s.byte7 = data.at(offset + 7);
    } else {  //大端
        //memcpy(&value, data.data() + offset, sizeof(double));
        udbl.s.byte0 = data.at(offset + 7);
        udbl.s.byte1 = data.at(offset + 6);
        udbl.s.byte2 = data.at(offset + 5);
        udbl.s.byte3 = data.at(offset + 4);
        udbl.s.byte4 = data.at(offset + 3);
        udbl.s.byte5 = data.at(offset + 2);
        udbl.s.byte6 = data.at(offset + 1);
        udbl.s.byte7 = data.at(offset);
    }

    return udbl.dbl;
}


